package cap

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"image/png"
	"math"
	"math/rand"
	"net/http"
	"os"
	"time"

	"github.com/golang/freetype"
	"github.com/golang/freetype/truetype"
	"golang.org/x/image/font"
)



// Captcha 验证码生成器结构
type Captcha struct {
	Width           int     // 图片宽度
	Height          int     // 图片高度
	MarginX         int     // 左右边距
	MarginY         int     // 上下边距
	FontSize        float64 // 字体大小
	MaxRotate       float64 // 最大旋转角度
	BgColor         color.RGBA
	TextColor       color.RGBA
	fontLoader      *FontLoader
	fontDir         string   // 字体目录
	image           *image.RGBA // 存储生成的图像
	CaptchaID       string      // 验证码ID
	CaptchaIDHeader string      // 响应头中验证码ID的名称
}

// NewCaptcha 创建验证码生成器实例
func NewCaptcha() *Captcha {
	// 使用智能字体目录查找函数
	defaultFontDir := GetDefaultFontDir()
	
	captcha := &Captcha{
		Width:           240,
		Height:          80,
		MarginX:         20,
		MarginY:         10,
		FontSize:        40,
		MaxRotate:       30,
		BgColor:         color.RGBA{240, 240, 240, 255},
		TextColor:       color.RGBA{0, 0, 0, 255},
		fontLoader:      NewFontLoader(),
		fontDir:         defaultFontDir, // 默认字体目录
		CaptchaIDHeader: "X-Captcha-ID", // 默认的头信息名称
	}

	return captcha
}

// LoadFontIfNeeded 加载字体（如果尚未加载）
func (c *Captcha) LoadFontIfNeeded() error {
	return c.fontLoader.LoadFontIfNeeded(c.fontDir)
}

// Generate 生成验证码图片
func (c *Captcha) Generate(text string) error {
	// 创建空白图片
	img := image.NewRGBA(image.Rect(0, 0, c.Width, c.Height))

	// 填充背景色
	draw.Draw(img, img.Bounds(), &image.Uniform{c.BgColor}, image.Point{}, draw.Src)

	// 加载字体
	if err := c.LoadFontIfNeeded(); err != nil {
		return err
	}

	// 计算每个字符的可用宽度
	availableWidth := c.Width - 2*c.MarginX
	charWidth := availableWidth / len(text)

	// 创建随机数生成器
	rand.Seed(time.Now().UnixNano())

	// 绘制文本
	ctx := freetype.NewContext()
	ctx.SetDPI(72)
	ctx.SetClip(img.Bounds())
	ctx.SetDst(img)
	ctx.SetHinting(font.HintingFull)

	for i, char := range text {
		// 尝试加载随机字体，最多尝试5次
		var ft *truetype.Font
		var fontFile []byte
		var fontPath string
		var err error
		var fontLoaded bool
		for j := 0; j < 5; j++ {
			fontFile, fontPath, err = c.fontLoader.TryLoadRandomFont()
			if err != nil {
				continue
			}
			ft, err = freetype.ParseFont(fontFile)
			if err == nil {
				fontLoaded = true
				break
			}
			// 将解析失败的字体添加到排除列表
			c.fontLoader.SetExcludedFonts([]string{fontPath})
			fmt.Printf("解析字体失败: %v, 字体文件: %s\n", err, fontPath)
		}
		if !fontLoaded {
			return fmt.Errorf("无法加载有效的字体文件")
		}

		// 设置字体和颜色
		ctx.SetFont(ft)
		ctx.SetFontSize(c.FontSize)
		ctx.SetSrc(&image.Uniform{c.getTextColor()})

		// 计算字符位置
		x := c.MarginX + i*charWidth + (charWidth-int(c.FontSize))/2
		y := c.Height/2 + int(c.FontSize)/3 // 垂直居中，略微偏下

		// 创建点并绘制字符
		pt := freetype.Pt(x, y)
		_, err = ctx.DrawString(string(char), pt)
		if err != nil {
			return err
		}
	}

	// 添加干扰线
	c.addInterferenceLines(img)

	// 添加噪点
	c.addNoise(img)

	// 存储生成的图像
	c.image = img
	return nil
}

// GetImage 获取生成的验证码图像
func (c *Captcha) GetImage() *image.RGBA {
	return c.image
}

// SaveToFile 将验证码保存到文件
func (c *Captcha) SaveToFile(filePath string) error {
	if c.image == nil {
		return fmt.Errorf("验证码图像未生成")
	}

	// 创建输出文件
	file, err := os.Create(filePath)
	if err != nil {
		return fmt.Errorf("创建文件失败: %w", err)
	}
	defer file.Close()

	// 将图片编码为PNG并写入文件
	if err := png.Encode(file, c.image); err != nil {
		return fmt.Errorf("编码验证码图片失败: %w", err)
	}

	return nil
}

// ToBase64 将验证码转换为base64编码字符串
func (c *Captcha) ToBase64() (string, error) {
	if c.image == nil {
		return "", fmt.Errorf("验证码图像未生成")
	}

	// 创建内存缓冲区
	buf := new(bytes.Buffer)

	// 将图片编码为PNG并写入缓冲区
	if err := png.Encode(buf, c.image); err != nil {
		return "", fmt.Errorf("编码验证码图片失败: %w", err)
	}

	// 转换为base64字符串
	base64Str := base64.StdEncoding.EncodeToString(buf.Bytes())

	// 返回带前缀的base64字符串
	return "data:image/png;base64," + base64Str, nil
}

// ServeHTTP 提供HTTP服务的方法，用于直接在Web应用中使用
func (c *Captcha) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if c.image == nil {
		http.Error(w, "验证码图像未生成", http.StatusInternalServerError)
		return
	}

	// 设置响应头
	w.Header().Set("Content-Type", "image/png")
	w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0")
	w.Header().Set("Pragma", "no-cache")
    
    // 如果设置了验证码ID，则在响应头中返回
    if c.CaptchaID != "" {
        w.Header().Set(c.CaptchaIDHeader, c.CaptchaID)
    }

	// 将图片编码为PNG并写入响应
	if err := png.Encode(w, c.image); err != nil {
		http.Error(w, "编码验证码图片失败", http.StatusInternalServerError)
		return
	}
}

// getTextColor 获取随机文本颜色（略微变化，增加验证码复杂性）
func (c *Captcha) getTextColor() color.RGBA {
	// 在基础颜色上添加小的随机变化
	red := c.clamp(int(c.TextColor.R) + rand.Intn(40) - 20)
	green := c.clamp(int(c.TextColor.G) + rand.Intn(40) - 20)
	blue := c.clamp(int(c.TextColor.B) + rand.Intn(40) - 20)

	return color.RGBA{
		R: uint8(red),
		G: uint8(green),
		B: uint8(blue),
		A: c.TextColor.A,
	}
}



// addInterferenceLines 添加干扰线
func (c *Captcha) addInterferenceLines(img *image.RGBA) {
	linesCount := 3 + rand.Intn(3) // 3-5条干扰线

	for i := 0; i < linesCount; i++ {
		// 随机线条颜色
		lineColor := color.RGBA{
			R: uint8(50 + rand.Intn(100)),
			G: uint8(50 + rand.Intn(100)),
			B: uint8(50 + rand.Intn(100)),
			A: uint8(100 + rand.Intn(100)),
		}

		// 随机线条起点和终点
		x1 := rand.Intn(c.Width)
		y1 := rand.Intn(c.Height)
		x2 := rand.Intn(c.Width)
		y2 := rand.Intn(c.Height)

		// 绘制线条
		c.drawLine(img, x1, y1, x2, y2, lineColor)
	}
}

// addNoise 添加噪点
func (c *Captcha) addNoise(img *image.RGBA) {
	noiseCount := c.Width * c.Height / 30 // 噪点数量

	for i := 0; i < noiseCount; i++ {
		x := rand.Intn(c.Width)
		y := rand.Intn(c.Height)

		// 随机噪点颜色
		noiseColor := color.RGBA{
			R: uint8(rand.Intn(100)),
			G: uint8(rand.Intn(100)),
			B: uint8(rand.Intn(100)),
			A: uint8(50 + rand.Intn(100)),
		}

		img.Set(x, y, noiseColor)
	}
}

// drawLine 绘制线条
func (c *Captcha) drawLine(img *image.RGBA, x1, y1, x2, y2 int, color color.RGBA) {
	dx := math.Abs(float64(x2 - x1))
	dy := math.Abs(float64(y2 - y1))
	var sx, sy int

	if x1 < x2 {
		sx = 1
	} else {
		sx = -1
	}

	if y1 < y2 {
		sy = 1
	} else {
		sy = -1
	}

	err := dx - dy

	for {
		img.Set(x1, y1, color)

		if x1 == x2 && y1 == y2 {
			break
		}

		e2 := 2 * err
		if e2 > -dy {
			err -= dy
			x1 += sx
		}
		if e2 < dx {
			err += dx
			y1 += sy
		}
	}
}

// clamp 确保值在0-255范围内
func (c *Captcha) clamp(value int) int {
	if value < 0 {
		return 0
	}
	if value > 255 {
		return 255
	}
	return value
}

// SetFontSize 设置字体大小
func (c *Captcha) SetFontSize(size float64) {
	c.FontSize = size
}

// SetFontDir 设置字体目录
func (c *Captcha) SetFontDir(fontDir string) {
	c.fontDir = fontDir
}

// SetMaxRotate 设置最大旋转角度
func (c *Captcha) SetMaxRotate(angle float64) {
	c.MaxRotate = angle
}

// SetBgColor 设置背景颜色
func (c *Captcha) SetBgColor(r, g, b, a uint8) {
	c.BgColor = color.RGBA{R: r, G: g, B: b, A: a}
}

// SetTextColor 设置文本颜色
func (c *Captcha) SetTextColor(r, g, b, a uint8) {
	c.TextColor = color.RGBA{R: r, G: g, B: b, A: a}
}

// SetCaptchaID 设置验证码ID
func (c *Captcha) SetCaptchaID(id string) {
	c.CaptchaID = id
}

// SetCaptchaIDHeader 设置响应头中验证码ID的名称
func (c *Captcha) SetCaptchaIDHeader(headerName string) {
	if headerName != "" {
		c.CaptchaIDHeader = headerName
	}
}
